# -*- coding: UTF-8 -*-
"""
@Project ：swift-forge-engine 
@File    ：jwt_auth_middleware.py
@IDE     ：PyCharm 
@Author  ：Tony.Gan
@Date    ：2025/2/20 22:12 
@Des     ：
"""
from typing import Any

from fastapi import Response, Request
from fastapi.security.utils import get_authorization_scheme_param
from starlette.authentication import AuthenticationError, AuthenticationBackend, AuthCredentials
from starlette.requests import HTTPConnection

from App.app.admin.schemas.sys_user_schema import CurrentUserInfo
from App.common.exception.errors import AuthorizationError
from App.common.security.jwt import jwt_authentication
from App.common.respones.response_code import StatusResponseCode
from App.config.conf import settings
from App.utils.serializers import MsgSpecJSONResponse


class _AuthenticationError(AuthenticationError):
    """重写内部认证错误类"""

    def __init__(self, *, code: int = None, message: str = None, headers: dict[str, Any] | None = None):
        self.code = code
        self.message = message
        self.headers = headers


class JwtAuthMiddleware(AuthenticationBackend):
    """JWT 认证中间件"""

    @staticmethod
    def auth_exception_handler(conn: HTTPConnection, exc: _AuthenticationError) -> Response:
        """覆盖内部认证错误处理"""
        return MsgSpecJSONResponse(content={'code': exc.code, 'message': exc.message, 'data': None},
                                   status_code=exc.code)

    async def authenticate(self, request: Request) -> tuple[AuthCredentials, CurrentUserInfo] | None:
        token = request.headers.get('Authorization')
        if not token:
            return

        if request.url.path in settings.TOKEN_REQUEST_PATH_EXCLUDE:
            return

        scheme, token = get_authorization_scheme_param(token)
        if scheme.lower() != 'bearer':
            return

        try:
            user = await jwt_authentication(token)
        except AuthorizationError as exc:
            raise _AuthenticationError(code=exc.code, message=exc.message)
        except Exception as e:
            from App import log
            log.error(f'JWT 授权异常：{e}')
            raise _AuthenticationError(code=getattr(e, 'code', StatusResponseCode.HTTP_500),
                                       message=getattr(e, 'message', 'JWT 授权异常'))

        return AuthCredentials(['authenticated']), user
